package com.sc.nft.service.impl;

import cn.hutool.core.util.ObjectUtil;
import com.sc.nft.dao.CollectionChainInitDetailsLogDao;
import com.sc.nft.dao.DigitalCollectionDao;
import com.sc.nft.entity.CollectionChainInitDetailsLog;
import com.sc.nft.entity.DigitalCollection;
import com.sc.nft.enums.CollectionChainDealStatusEnum;
import com.sc.nft.enums.RedisKeyEnum;
import com.sc.nft.enums.UserChainLogStatusEnum;
import com.sc.nft.exception.GlobalRunTimeException;
import com.sc.nft.service.CollectionChainInitDetailsLogService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.redisson.Redisson;
import org.redisson.api.RLock;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * 藏品初始化上链记录详情表服务接口实现
 *
 * @author Sun
 * @description 由 Mybatisplus Code Generator 创建
 * @since 2023-04-18 14:28:42
 */
@Slf4j
@RequiredArgsConstructor
@Service
public class CollectionChainInitDetailsLogServiceImpl implements CollectionChainInitDetailsLogService {
    private final CollectionChainInitDetailsLogDao collectionChainInitDetailsLogDao;
    private final DigitalCollectionDao digitalCollectionDao;
    private final Redisson redisson;
    private final RedisTemplate redisTemplate;

    @Override
    public List<CollectionChainInitDetailsLog> metaChainInitListAndCollectionIdAndLimit(Long collectionId,UserChainLogStatusEnum status, CollectionChainDealStatusEnum dealStatus,int size) {
        return collectionChainInitDetailsLogDao.metaChainInitListAndCollectionIdAndLimit(collectionId, status, dealStatus,size);
    }

    @Override
    public List<CollectionChainInitDetailsLog> getOneTypeListByStatusAndDealStatus(UserChainLogStatusEnum status, CollectionChainDealStatusEnum dealStatus) {
        Long collectionId = collectionChainInitDetailsLogDao.getOneTypeIds(status, dealStatus);
        if (ObjectUtil.isNull(collectionId)) {
            return null;
        }

        DigitalCollection digitalCollection = digitalCollectionDao.getById(collectionId);
        if (ObjectUtil.isNull(digitalCollection)) {
            return null;
        }

        return collectionChainInitDetailsLogDao.getListByStatusAndDealStatusAndCollectionId(digitalCollection.getId(), status, dealStatus);
    }

    @Override
    public Integer getCountByStatusAndChainStatusAndCollectionId(UserChainLogStatusEnum status, CollectionChainDealStatusEnum dealStatus, Long collectionId) {
        return collectionChainInitDetailsLogDao.getCountByStatusAndChainStatusAndCollectionId(status, dealStatus, collectionId);
    }

    @Override
    public CollectionChainInitDetailsLog getCanTransfer(Long collectionId) {
        RLock lock = redisson.getLock(RedisKeyEnum.GET_COLLECTION_TRANSFER.getKey() + collectionId.toString());
        try {
            boolean res = lock.tryLock(5, TimeUnit.SECONDS);
            if (res) {
                Long size = redisTemplate.opsForList().size(RedisKeyEnum.QUEUE_COLLECTION_ID.getKey() + collectionId.toString());
                log.info("collectionId:{},size:{}",collectionId,size);
                if (size == null || size == 0) {
                    initCollectionQueue(collectionId);
                }
                Object id = redisTemplate.opsForList().rightPop(RedisKeyEnum.QUEUE_COLLECTION_ID.getKey() + collectionId.toString());
                if (ObjectUtil.isNull(id)) {
                    throw new GlobalRunTimeException("当前没有可流转藏品");
                }
                log.info("collectionId:{},chainLogsId:{}",collectionId,id);

                return collectionChainInitDetailsLogDao.getById(Long.parseLong(id.toString()));
            }
        } catch (InterruptedException e) {
            throw new GlobalRunTimeException("获取可流转藏品失败");
        } finally {
            lock.unlock();
        }
        throw new  GlobalRunTimeException("获取可流转藏品失败");
    }

    private void initCollectionQueue(Long collectionId) {
        List<Long> transferIds = collectionChainInitDetailsLogDao.getWithTransferQueue(collectionId);
        Set<String> sets = transferIds.stream().map(Object::toString).collect(Collectors.toSet());
        redisTemplate.opsForList().leftPushAll(RedisKeyEnum.QUEUE_COLLECTION_ID.getKey() + collectionId.toString(), sets);
        redisTemplate.expire(RedisKeyEnum.QUEUE_COLLECTION_ID.getKey() + collectionId.toString(),24L,TimeUnit.HOURS);
    }

    @Override
    public Boolean updateContractAddressAndTransactionHashAndStatusAndDealStatusByIds(String contractAddress, String transactionHash, UserChainLogStatusEnum userChainLogStatusEnum, CollectionChainDealStatusEnum collectionChainDealStatusEnum, List<Long> ids) {
        return collectionChainInitDetailsLogDao.updateContractAddressAndTransactionHashAndStatusAndDealStatusByIds(contractAddress, transactionHash, userChainLogStatusEnum, collectionChainDealStatusEnum, ids);
    }

    @Override
    public Boolean updateContractAddressAndTransactionHashAndStatusAndDealStatusById(String contractAddress, String transactionHash, UserChainLogStatusEnum userChainLogStatusEnum, CollectionChainDealStatusEnum collectionChainDealStatusEnum, Long id) {
        return collectionChainInitDetailsLogDao.updateContractAddressAndTransactionHashAndStatusAndDealStatusById(contractAddress, transactionHash, userChainLogStatusEnum, collectionChainDealStatusEnum, id);
    }

}